题解:B4392 [常州市赛 2025] 压缩

604 字
3 分钟
题解:B4392 [常州市赛 2025] 压缩

题面传送门:B4392 [常州市赛 2025] 压缩

题目大意#

给个含 0,1 与通配符 # 的字符串(通配符可任意赋值为 0,1),相同的字串可以消到只剩下一个,求消完后最短的字串长度(答案唯一)。

思路讲解#

可以从测试点的特殊性质入手。若字符串中无 0,则说明剩下的一定是 1 或通配符,通配符赋值为 1,答案为 1。同理,若没有 1,答案就是 0。

若字符串长度不超过 33,则答案串的长度不会超过 33。列举答案串的所有情况如下:

字符串长度情况 11情况 22情况 33情况 44情况 55情况 66情况 77情况 88
110
200 (压缩为 0)011011 (压缩为 1)
3000(压缩为 0)001 (压缩为 01)010011(压缩为 01)100(压缩为 10)101110(压缩为 10)111 (压缩为 1)

情况数屈指可数,进一步思考后发现,这些情况其实就只有以下几种答案:
1,0,01,10,101,010。

观察这些答案和原情况的关系,得出来一个基本分类讨论框架:

  1. 如果 1 与 0 不同时存在,那么即使有通配符,也可以构造一个长度为 11 的答案。
  2. 如果原串长度大于等于 22,且其头尾不等,那么中间部分(长度为 22 无中间,直接输出)的每一个数都可以通过头尾两个不同的数构造子串进行消除,消除到 01 或 10。
  3. 若长度大于 22,头尾相等,则也可以构造子串消除到 010 或 101。

发现了疑点,通配符该怎么办呢?如果字符串不满足上方的条件 11,那就让其优先满足条件 22,因为其答案相对较短。找到通配符所在位置,与另外一个头或尾位置字符相反就可以了。

不可能有通配符同时在头尾的情况,若同时在头尾,构造出来条件 22 会发现有两个答案。

此框架有推广性,可以用于任意长度的字符串,所以问题就解决了。

代码实现#

完整代码
#include<bits/stdc++.h>
using namespace std;
string s;
char c1,c2;
bool b[2];
int main(){
cin>>s;
for(int i=0;i<s.size();i++){
if(s[i]!='#') b[s[i]-'0']=1;
}
if(b[1]==1&&b[0]==0){
cout<<1;
}else if(b[1]==0&&b[0]==1){
cout<<0;
}else{
c1=s[0];c2=s[s.size()-1];
if(c1!=c2){
if(c1=='#'){
if(c2=='0') cout<<"10";
else cout<<"01";
}else if(c2=='#'){
if(c1=='1') cout<<"10";
else cout<<"01";
}else{
cout<<c1<<c2;
}
}else{
if(c1=='0'){
cout<<"010";
}else if(c1=='1'){
cout<<"101";
}
}
}
return 0;
}

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

题解:B4392 [常州市赛 2025] 压缩
https://zhedaotixuanbo.pages.dev/posts/题解:B4392 [常州市赛 2025] 压缩/
作者
zhedaotixuanbo
发布于
2026-10-04
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
zhedaotixuanbo
这道题选什么? _____!
公告
分类
标签
站点统计
文章
17
分类
1
标签
21
总字数
6,295
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
Cloudflare Pages
博客版本
ZTXB v1.0.0
文章许可
CC BY-NC-SA 4.0